/* 
 * [New BSD License (BSD 3-Clause License)]
 * Copyright (c) 2012, Max Bechtold
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 *     - Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     - Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     - Neither the name of the Rel2Xml Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package maxbe.rel2xml.generator.docs;

import static maxbe.rel2xml.util.Config.getBoolean;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import maxbe.rel2xml.util.Config;

import org.apache.log4j.Logger;

/**
 * Class for creating TransformerHandlers that operate on different files
 * according to defined TableMapping
 * 
 * @author Max Bechtold
 * 
 */
public class HandlerController {

	private static Logger log = Logger.getLogger(HandlerController.class);

	private List<PrintWriter> writers;
	private List<TransformerHandler> handlers;

	private SAXTransformerFactory stf;
	private TransformerHandler defaultHandler;

	private File directory;
	private String database;

	public HandlerController(File dir, String database) throws IOException {
		this.database = database;

		directory = dir;
		if (!directory.exists() && !directory.mkdirs()) {
			String msg = String.format("Unable to create directory '%s'",
					dir.getName());
			log.error(msg);
			throw (new IOException(msg));
		}

		writers = new ArrayList<PrintWriter>();
		handlers = new ArrayList<TransformerHandler>();

		stf = (SAXTransformerFactory) TransformerFactory.newInstance();
	}

	public TransformerHandler getHandler()
			throws TransformerConfigurationException, IOException {
		if (defaultHandler == null) {
			defaultHandler = newHandler(directory, database);
		}
		return defaultHandler;
	}

	public TransformerHandler getHandler(String table)
			throws TransformerConfigurationException, IOException {
		return newHandler(new File(directory, database + "_tables"), table);
	}

	public TransformerHandler getHandler(String table, int id)
			throws TransformerConfigurationException, IOException {
		return newHandler(new File(directory, database + "_tables" + '/'
				+ table + "_tuples"), table + '#' + id);
	}

	private TransformerHandler newHandler(File directory, String fileName)
			throws TransformerConfigurationException, IOException {
		TransformerHandler handler = null;
		PrintWriter out = null;

		try {
			if (!directory.exists() && !directory.mkdirs()) {
				throw (new IOException("Could not create directory "
						+ directory));
			}
			out = new PrintWriter(new BufferedWriter(new FileWriter(new File(
					directory, fileName + ".xml"))));
			StreamResult streamResult = new StreamResult(out);

			handler = stf.newTransformerHandler();

			Transformer transformer = handler.getTransformer();
			transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			transformer.setOutputProperty(OutputKeys.METHOD, "xml");

			if (getBoolean(Config.PRETTY_PRINT)) {
				transformer.setOutputProperty(OutputKeys.INDENT, "yes");
				transformer.setOutputProperty(
						"{http://xml.apache.org/xslt}indent-amount", "4");
			}

			handler.setResult(streamResult);

		} catch (TransformerConfigurationException e) {
			// Should not occur
			log.error(e);
			throw (e);
		} catch (IOException e) {
			log.error(e.getStackTrace());
			throw (e);
		}

		writers.add(out);
		handlers.add(handler);

		return handler;
	}

	public void terminateHandler(TransformerHandler handler) {
		int index = handlers.indexOf(handler);
		PrintWriter out = writers.get(index);
		out.flush();
		out.close();
		writers.remove(index);
		handlers.remove(index);
	}
}
